package c.x.jy.service.utils.wechat;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.DigestException;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.UUID;

import javax.net.ssl.SSLContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import c.x.jy.common.utils.SHA1;

 
@SuppressWarnings("all")
public class WechatCommonUtil {
	
	
	 // 解析xml
    public static Map<String,Object> getMapFromXML(String xmlString) {
        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    	//String FEATURE = null;
        DocumentBuilder builder;
        InputStream is = null;
        Document document =null;
        try {
	    	factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	    	factory.setXIncludeAware(false);
	    	factory.setExpandEntityReferences(false);
		} catch (Exception e) {
		e.printStackTrace();
		}
		try {
			builder = factory.newDocumentBuilder();
		     is =  getStringStream(xmlString);
	         document = builder.parse(is);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			 try {
				 if(is!=null)
				is.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
        //获取到document里面的全部结点
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        Map<String, Object> map = new HashMap<String, Object>();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
                map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        return map;
    }


/*    // 解析xml
    public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException ,Exception{
        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is =  getStringStream(xmlString);
        Document document = builder.parse(is);
        //获取到document里面的全部结点
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        Map<String, Object> map = new HashMap<String, Object>();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
                map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        is.close();
        return map;
    }*/

    /** 将字符串转换为输入流
     * @param inputString 需要转换的字符串
     * @return
     * @throws Exception
     */
    private static InputStream getStringStream(String inputString) throws Exception{
        ByteArrayInputStream tInputStringStream = null;
        if (inputString != null && !inputString.trim().equals("")) {
            tInputStringStream = new ByteArrayInputStream(inputString.getBytes("utf-8"));
        }
        return tInputStringStream;
    }

    /** 将排序的map转成xml
     * @param parameters 需要转换的map
     * @return
     */
    public static String getRequestXml(SortedMap<String,Object> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String key = (String)entry.getKey();
            String value = (String)entry.getValue();
            if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
                sb.append("<"+key+">"+"<![CDATA["+value+"]]></"+key+">");
            }else {
                sb.append("<"+key+">"+value+"</"+key+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**指定请求方式发送请求
     * @param requestUrl 请求的URL
     * @param requestMethod 请求的方式
     * @param outputStr 携带的参数
     * @return 发送http请求
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时：{}"+ ce);
        } catch (Exception e) {
            System.out.println("https请求异常：{}"+ e);
        }
        return null;
    }

    /**
     * 发送GET请求
     * @param url
     */
    public static String sendGet(String url) throws Exception {
        URL realUrl= null;
        BufferedReader bufferedReader = null;
        String result = "";
        try {
            realUrl = new URL(url);
            URLConnection connection=realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            InputStream inputStream = connection.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
             bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                result += line;
            }
        } catch (MalformedURLException e) {
            throw new Exception("发送GET请求失败，URL格式错误"+getStackTraceAsString(e));
        } catch (IOException e) {
            throw new Exception("发送GET请求失败,开启连接异常"+getStackTraceAsString(e));
        }finally {
            if (bufferedReader!=null)
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return  result;
    }

    /**
     * 发送POST请求
     * @param url
     * @param param
     */
    public static String sendPost(String url, String param) throws Exception {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        URL realUrl = null;
        try {
            realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (MalformedURLException e) {
            throw new Exception("发送POST请求失败，URL格式错误"+getStackTraceAsString(e));
        }catch (IOException e) {
            e.printStackTrace();
        } finally{
            try{
                if(out!=null)
                    out.close();
                if(in!=null)
                    in.close();
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    public static String sendSSLPost(String url,String data,String mchId,String caPath) {
        try {
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            //P12文件目录 证书路径，这里需要你自己修改，linux下还是windows下的根路径
            String filepath = caPath;
            FileInputStream instream = new FileInputStream(filepath+"apiclient_cert.p12");
            try {
                keyStore.load(instream, mchId.toCharArray());//这里写密码..默认是你的MCHID
            } finally {
                instream.close();
            }

            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, mchId.toCharArray())//这里也是写密码的
                    .build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();

            HttpPost httpost = new HttpPost(url); // 设置响应头信息
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**生成一定位数的随机数带字符.
     * @param length 生成字符串的长度
     * @return
     */
  

    //最好不要超过32位
    public static String createNonceStr(int length) {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0,length);
    }

    public static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }


    public static String getStackTraceAsString(Throwable throwable) {
        StringWriter stringWriter = new StringWriter();
        throwable.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }

   /**
    * 签名
    * @param weixin
    * @throws DigestException
    */
	public static void getSignature(WechatConfig weixin) throws DigestException {
		String str = "jsapi_ticket=" + weixin.getJsapiTicket() + "&noncestr=" + weixin.getNonceStr() + "&timestamp="
				+ weixin.getTimestamp() + "&url=" + weixin.getUrl();
		weixin.setSignature(SHA1.SHAStr(str).toLowerCase());
	}
/**
 * 微信支付返回签名认证
 * @param smap
 * @param apiKey
 * @return
 */
	@SuppressWarnings("rawtypes")
	public static boolean isWechatSign(SortedMap<String, Object> smap, String apiKey) {
		StringBuffer sb = new StringBuffer();
		Set es = smap.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + apiKey);
		/** 验证的签名 */
		String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase();
		/** 微信端返回的合法签名 */
		String validSign = ((String) smap.get("sign")).toUpperCase();
		return validSign.equals(sign);
	}
}
